package com.xiaoma.aes.encryption.asymmetrical;

import com.xiaoma.aes.util.BaseUtil;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;



/**
 * 数据签名工具类
 * @author Knight-Ran 2016年5月3日 下午4:51:23
 */
public class SignatureTool{
    
    /**
     * 用私钥对信息生成数字签名
     * @param data 加密数据
     * @param privateKey 私钥
     * @return
     * @throws Exception
     */
    public static String sign(String data, String privateKey){
        
        /* 对公钥解密 */
        byte [] keyBytes = BaseUtil.parseHexStr2Byte(privateKey);
        
        
        /* 构造PKCS8EncodedKeySpec对象 */
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        
        /* KEY_ALGORITHM 指定的加密算法 */
        KeyFactory keyFactory = null;
        /* 取私钥匙对象 */
        PrivateKey priKey = null;
        try{
            keyFactory = KeyFactory.getInstance(Encrytion.KEY_ALGORTHM);
            priKey = keyFactory.generatePrivate(pkcs8KeySpec);
        }catch(NoSuchAlgorithmException e){
//            LOGGER.error("系统异常:签名算法(" + Encrytion.KEY_ALGORTHM + ")不存在", e);
//            throw new EncryptionException("系统异常:签名算法({0})不存在", Encrytion.KEY_ALGORTHM);
        }catch(InvalidKeySpecException e){
//            LOGGER.error("业务异常: 秘钥获取失败", e);
//            throw new EncryptionException("业务异常: 秘钥获取失败", e);
        }
        
        
        /* 用私钥对信息生成数字签名 */
        Signature signature = null;
        try{
            signature = Signature.getInstance(Encrytion.SIGNATURE_ALGORITHM);
            signature.initSign(priKey);
        }catch(NoSuchAlgorithmException e){
//            LOGGER.error("业务异常: 秘钥无效", e);
//            throw new EncryptionException("业务异常: 秘钥无效", e);
        }catch(InvalidKeyException e){
//            LOGGER.error("系统异常:签名算法(" + Encrytion.KEY_ALGORTHM + ")不存在", e);
//            throw new EncryptionException("系统异常:签名算法({0})不存在", Encrytion.KEY_ALGORTHM);
        }
        
        
        byte [] dataBytes = null;
        try{
            dataBytes = data.getBytes(Encrytion.CHARSET);
            signature.update(dataBytes);
            return BaseUtil.parseByte2HexStr(signature.sign());
        }catch(UnsupportedEncodingException e){
//            LOGGER.error("业务异常: 获取签名数据字节数组异常, 字符编码为" + Encrytion.CHARSET, e);
//            throw new EncryptionException("业务异常: 获取签名数据字节数组异常, 字符编码为{0}", e, Encrytion.CHARSET);
        }catch(SignatureException e){
//            LOGGER.error("业务异常: 签名数据验证异常", e);
//            throw new EncryptionException("业务异常: 签名数据验证异常", e);
        }

        return null;
    }
    
    /**
     * 校验数字签名
     * @param data 加密数据
     * @param publicKey 公钥
     * @param sign 数字签名
     * @return
     * @throws Exception
     */
    public static boolean verify(String data, String publicKey, String sign){
        
        /* 解密公钥 */
        byte [] keyBytes = BaseUtil.parseHexStr2Byte(publicKey);
        
        /* 构造X509EncodedKeySpec对象 */
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        
        /* KEY_ALGORITHM 指定的加密算法 */
        KeyFactory keyFactory;
        // 取公钥匙对象
        PublicKey pubKey = null;
        try{
            keyFactory = KeyFactory.getInstance(Encrytion.KEY_ALGORTHM);
            pubKey = keyFactory.generatePublic(keySpec);
        }catch(NoSuchAlgorithmException e){
//            LOGGER.error("系统异常:加密算法(" + Encrytion.KEY_ALGORTHM + ")不存在", e);
//            throw new EncryptionException("系统异常:加密算法({0})不存在", Encrytion.KEY_ALGORTHM);
        }catch(InvalidKeySpecException e){
//            LOGGER.error("业务异常: 秘钥获取失败", e);
//            throw new EncryptionException("业务异常: 秘钥获取失败", e);
        }
        
        Signature signature = null;
        try{
            signature = Signature.getInstance(Encrytion.SIGNATURE_ALGORITHM);
            signature.initVerify(pubKey);
        }catch(NoSuchAlgorithmException e){
//            LOGGER.error("系统异常:签名算法(" + Encrytion.KEY_ALGORTHM + ")不存在", e);
//            throw new EncryptionException("系统异常:签名算法({0})不存在", Encrytion.KEY_ALGORTHM, e);
        }catch(InvalidKeyException e){
//            LOGGER.error("业务异常: 秘钥无效", e);
//            throw new EncryptionException("业务异常: 秘钥无效", e);
        }
        
        byte [] dataBytes;
        try{
            dataBytes = data.getBytes(Encrytion.CHARSET);
            /* 验证签名是否正常 */
            signature.update(dataBytes);
            return signature.verify(BaseUtil.parseHexStr2Byte(sign));
        }catch(UnsupportedEncodingException e){
//            LOGGER.error("业务异常: 获取签名数据字节数组异常, 字符编码为" + Encrytion.CHARSET, e);
//            throw new EncryptionException("业务异常: 获取签名数据字节数组异常, 字符编码为{0}", e, Encrytion.CHARSET);
        }catch(SignatureException e){
//            LOGGER.error("业务异常: 签名数据验证异常", e);
//            throw new EncryptionException("业务异常: 签名数据验证异常", e);
        }

        return false;
    }
}
